﻿using System;
using System.ComponentModel;
using System.Linq;
using System.Xml;
using Aeon.Configuration;

namespace Aeon.Emulator.Input
{
    /// <summary>
    /// Describes game port settings.
    /// </summary>
    [Category("Input")]
    [DeviceConfiguration("Aeon.GamePort")]
    public sealed class GamePortConfiguration : DeviceConfiguration
    {
        private Guid? joystickA;
        private Guid? joystickB;

        /// <summary>
        /// Initializes a new instance of the <see cref="GamePortConfiguration"/> class.
        /// </summary>
        public GamePortConfiguration()
            : base("Game Port")
        {
            this.ControllerA = DirectInput.GetInstance().GetDevices(DeviceClass.GameController, DeviceEnumFlags.AttachedOnly).FirstOrDefault();
        }

        /// <summary>
        /// Gets or sets the first controller.
        /// </summary>
        [Browsable(true)]
        [InputDeviceConstraint]
        [DisplayName("Controller A")]
        public DeviceInfo ControllerA
        {
            get
            {
                if(this.JoystickA == null)
                    return null;

                return DirectInput.GetInstance().GetDeviceInfo((Guid)this.JoystickA);
            }
            set
            {
                if(value == null)
                    this.JoystickA = null;
                else
                    this.JoystickA = value.InstanceId;
            }
        }
        /// <summary>
        /// Gets or sets the second controller.
        /// </summary>
        [Browsable(true)]
        [InputDeviceConstraint]
        [DisplayName("Controller B")]
        public DeviceInfo ControllerB
        {
            get
            {
                if(this.JoystickB == null)
                    return null;

                return DirectInput.GetInstance().GetDeviceInfo((Guid)this.JoystickB);
            }
            set
            {
                if(value == null)
                    this.JoystickB = null;
                else
                    this.JoystickB = value.InstanceId;
            }
        }

        /// <summary>
        /// Gets or sets the ID of the first input device.
        /// </summary>
        public Guid? JoystickA
        {
            get { return this.joystickA; }
            set
            {
                if(this.joystickA != value)
                {
                    this.joystickA = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("JoystickA"));
                    OnPropertyChanged(new PropertyChangedEventArgs("ControllerA"));
                }
            }
        }
        /// <summary>
        /// Gets or sets the ID of the second input device.
        /// </summary>
        public Guid? JoystickB
        {
            get { return this.joystickB; }
            set
            {
                if(this.joystickB != value)
                {
                    this.joystickB = value;
                    OnPropertyChanged(new PropertyChangedEventArgs("JoystickB"));
                    OnPropertyChanged(new PropertyChangedEventArgs("ControllerB"));
                }
            }
        }

        /// <summary>
        /// Returns a new instance of the emulated device.
        /// </summary>
        /// <param name="p">Extra parameters which may be used for initialization.</param>
        /// <returns>New instance of the emulated device.</returns>
        public override IVirtualDevice Create(CreateDeviceParameters p)
        {
            return new JoystickDevice(p.WindowHandle, this.JoystickA, this.JoystickB);
        }
        /// <summary>
        /// Returns a deep copy of the device configuration.
        /// </summary>
        /// <returns>Deep copy of the device configuration.</returns>
        public override IDeviceConfiguration Clone()
        {
            return new GamePortConfiguration()
            {
                IsEnabled = this.IsEnabled,
                JoystickA = this.JoystickA,
                JoystickB = this.JoystickB
            };
        }

        /// <summary>
        /// Serializes the configuration to an XML element.
        /// </summary>
        /// <param name="xmlWriter">XmlWriter used to serialize the object.</param>
        protected override void Serialize(XmlWriter xmlWriter)
        {
            base.Serialize(xmlWriter);

            if(this.JoystickA != null)
                xmlWriter.WriteAttributeString("JoystickA", this.JoystickA.ToString());
            if(this.JoystickB != null)
                xmlWriter.WriteAttributeString("JoystickB", this.JoystickB.ToString());
        }
        /// <summary>
        /// Deserializes the configuration from an XML element.
        /// </summary>
        /// <param name="xmlReader">XmlReader used to deserialize the object.</param>
        protected override void Deserialize(XmlReader xmlReader)
        {
            base.Deserialize(xmlReader);

            var joystickA = xmlReader.GetAttribute("JoystickA");
            if(!string.IsNullOrEmpty(joystickA))
                this.JoystickA = Guid.Parse(joystickA);

            var joystickB = xmlReader.GetAttribute("JoystickB");
            if(!string.IsNullOrEmpty(joystickB))
                this.JoystickB = Guid.Parse(joystickB);
        }
    }
}
